using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Globalization;

using ca.metaobjects.csogateway.Reflection;

namespace ca.metaobjects.csogateway.Controls
{
	/// <summary>
	/// The Importer control renders scripts tags for various script files needed on the client side. The Importer control does not need to be
	/// explicitely given the location of the script to import, this will be infered from the type of the object given to the ObjectGateway
	/// controls on the page.
	/// </summary>
	[ToolboxData("<{0}:Importer runat=\"server\"></{0}:Importer>")]
	public class Importer : Control
	{
		/// <summary>
		/// Enumeration used by property <see cref="Importer.MsAjaxLibraryVersion" /> to specify which
		/// version of the MicrosoftAjax.js library should be Imported.
		/// </summary>
		/// <value>
		///		<c>None</c> means that no Microsoft.Ajax library should be imported.
		///		<c>v1_0</c> stands for version 1.0.61025.0 and <c>v3_5</c> stands for version 3.5.30729.1
		///	</value>
		public enum MicrosoftAjaxLibraryVersion
		{
			/// <summary>
			/// No Microsoft.Ajax library should be imported
			/// </summary>
			None = 0,
			/// <summary>
			/// Version 1.0.61025.0 should be imported
			/// </summary>
			v1_0 = 1,
			/// <summary>
			/// Version 3.5.30729.1 should be imported
			/// </summary>
			v3_5 = 2
		}

		private static readonly string msAjaxScriptsFilename = "MicrosoftAjax.js";
		private static readonly string csoGatewayGlobalFunctionsFilename = "CsoGatewayGlobalFunctions.js";

		DependencyGraph previousDependencyGraph = null;

		private MicrosoftAjaxLibraryVersion msAjaxLibraryVersion = MicrosoftAjaxLibraryVersion.None;
		/// <summary>
		/// Gets or sets a value of the <see cref="Importer.MicrosoftAjaxLibraryVersion" /> enum indicating
		/// which version of the Microsoft.Ajax.js library to import.
		/// If the CSO Gateway is used in conjunction with Microsoft Ajax, it might not be necessary to import the MicrosoftAjax.js file, so
		/// this attribute should be set to <c>None</c>. If the CSO Gateway is used alone this should be set to <c>v1_0</c> or <c>v3_5</c>.
		/// </summary>
		public MicrosoftAjaxLibraryVersion MsAjaxLibraryVersion
		{
			get
			{
				return msAjaxLibraryVersion;
			}
			set
			{
				msAjaxLibraryVersion = value;
			}
		}


		private bool importMsAjaxScripts;
		/// <summary>
		/// Gets or sets a value indicating whether the MicrosoftAjax.js file should be imported.
		/// If the CSO Gateway is used in conjunction with Microsoft Ajax, it might not be necessary to import the MicrosoftAjax.js file, so
		/// this attribute should be set to false. If the CSO Gateway is used alone this should be set to true.
		/// </summary>
		/// <remarks>This property is obsolete and will be removed in version 1.0. Use Importer.MsAjaxLibraryVersion</remarks>
		[Obsolete("Use Importer.MsAjaxLibraryVersion property instead.")]
		public bool ImportMsAjaxScripts
		{
			get
			{
				return importMsAjaxScripts;
			}
			set
			{
				importMsAjaxScripts = value;
			}
		}

		/// <summary>
		/// Uses the init event to call <see cref="System.Web.UI.Page.RegisterRequiresControlState"/>
		/// </summary>
		/// <param name="e">Event arguments</param>
		protected override void OnInit(EventArgs e)
		{
			base.OnInit(e);
			Page.RegisterRequiresControlState(this);
		}

		/// <summary>
		/// Restores control-state information from a previous page request that was saved by the SaveControlState method. The restored control-state
		/// is the set of script to import and dependencies between them.
		/// </summary>
		/// <param name="savedState">An Object that represents the control state to be restored. </param>
		protected override void LoadControlState(object savedState)
		{
			previousDependencyGraph = (DependencyGraph)savedState;
		}

		/// <summary>
		/// Saves any server control state changes that have occurred since the time the page was posted back to the server. The control-state
		/// that will be saved is the set of script/dependencies of this request merge with those of the previous request.
		/// </summary>
		/// <returns>Returns the server control's current state or null if there is no state. </returns>
		protected override object SaveControlState()
		{
			if(previousDependencyGraph != null)
				DependencyGraph.ForCurrentHttpRequest.Merge(previousDependencyGraph);

			return DependencyGraph.ForCurrentHttpRequest;
		}
		
		/// <summary>
		/// Create a new Importer control
		/// </summary>
		public Importer()
		{
		}

		/// <summary>
		/// Render all the script tags in an order that respects dependencies between them.
		/// </summary>
		/// <param name="writer">The writer to write the response to.</param>
		protected override void Render(HtmlTextWriter writer)
		{
			writer.Write(writer.NewLine);

			if (msAjaxLibraryVersion == MicrosoftAjaxLibraryVersion.v1_0 || msAjaxLibraryVersion == MicrosoftAjaxLibraryVersion.v3_5)
			{
				writer.Write("<script type=\"text/javascript\" src=\"csogateway.axd?import=");

				if (msAjaxLibraryVersion == MicrosoftAjaxLibraryVersion.v1_0)
				{
					writer.Write("_1._0._61025._0.");
				}
				else // v3_5
				{
					writer.Write("_3._5._0._0._3._5._30729._1.");
				}

				writer.Write(Page.Server.UrlEncode(msAjaxScriptsFilename));
				writer.Write("\"></script>");

				writer.Write(writer.NewLine);
			}
			
			writer.Write("<script type=\"text/javascript\" src=\"csogateway.axd?import=");
			writer.Write(Page.Server.UrlEncode(csoGatewayGlobalFunctionsFilename));
			writer.Write("\"></script>");
			
			writer.Write(writer.NewLine);

			List<DependencyGraph.ScriptDescriptor> scriptDescriptorsList = DependencyGraph.ForCurrentHttpRequest.generateTopologicalOrder();

			for (int i = (scriptDescriptorsList.Count - 1); i >= 0; --i)
			{
				writer.Write("<script type=\"text/javascript\" src=\"");
				if (scriptDescriptorsList[i].descriptorType == DependencyGraph.DescriptorType.CsoGeneratedTypeName || scriptDescriptorsList[i].descriptorType == DependencyGraph.DescriptorType.CsoNativeScriptFile)
				{
					writer.Write("csogateway.axd?import=");
					writer.Write(Page.Server.UrlEncode(scriptDescriptorsList[i].descriptor));
				}
				else
				{
					writer.Write(scriptDescriptorsList[i].descriptor);
				}
				writer.Write("\"></script>");
				writer.Write(writer.NewLine);
			}
		}
	}
}
